/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package megachess.svn;

import java.io.*;
import java.util.*;

/**
 *
 * @author andi
 */
public class MegaChessSvn {

    /**
     * @param args the command line arguments
     */
    static Board myBoard;
    static char myColor;
    static Client server;
    static long startTime;
    static int loopCounter;
    static boolean timeOver;
    static Move m0;
    static Move m0temp;
    static Move m0negamax;

    public static void main(String[] args) {
        // TODO code application logic here
        myBoard = new Board();
        //myBoard.printToOutputStream();
        // myBoard.BoardfromInputStream();
        myBoard.toCommandLine();



        initializeNetwork();




        String currentMoveString;
        char status = '?';
        Move currentMove;
        while (status == '?') {
            if (myBoard.getOnMove() == 'W') {
                //move local bot
//                currentMove = chessBot_optimized();
//                status = myBoard.move(currentMove);
//                System.out.println("White moved:  " + currentMove.getMoveString());
                myBoard.toCommandLine();



                
                 //#####Client Server 
                if (myColor=='W') //move network
                 status=sendServerMove(server, chessBot_optimized()); 
                else
                 status=receiveServerMove(server);
                    //#####end Client Server


            } else if (myBoard.getOnMove() == 'B') {
                //local Random-Player   
//                 currentMove=RandomChessBot();
//                currentMove = chessBot();
                //System.out.println(currentMove.getMoveString());

                //currentMove = chessBot_bestMove();
                //System.out.println(currentMove.getMoveString());

//                status = myBoard.move(currentMove);
//                System.out.println("Black moved:  " + currentMove.getMoveString());
                myBoard.toCommandLine();
//                       read("break");  

                
                
                
                
                  //#####Client Server 
                if (myColor=='B')
                  status=sendServerMove(server, chessBot_optimized()); 
                else
                  status=receiveServerMove(server); //#####end Client Server
                 
                //#######Manual input
                   /*
                 * myBoard.toCommandLine(); * do{ currentMoveString=read("please
                 * enter your draw: "); status=myBoard.move(currentMoveString);
                 * }while (status=='X');
                 */
            }//endif
        }//endwhile
        myBoard.status = status;
        myBoard.toCommandLine();
        myBoard.printStatusReport();
        //currentMove.printMove();
    }//end method main

    public static Move chessBot_negamax(int depth) {
        System.out.println("Farbe: " + myBoard.getOnMove());
        timeOver = false;
        negamax_classic(myBoard, depth, true);
        return m0temp;
    }//endmethod

    public static Move chessBot() {
        startTime = System.currentTimeMillis();
        loopCounter = 0;
        timeOver = false;
        int depth = 0;
        int value;

        while (timeOver == false) {
            depth++;
            value = negamax(myBoard, depth, true, -9000, 9000);
            //System.out.println(m0temp.getMoveString() + ": " + value);
            if (timeOver == false) {
                m0 = m0temp;
            }
        }//endwhile
        System.out.println("Reached depth : " + depth);

        Move choosenMove = m0;
        return choosenMove;
    }//end method

    public static Move chessBot_optimized() {
        startTime = System.currentTimeMillis();
        loopCounter = 0;
        timeOver = false;
        int depth = 0;
        int value = 0;
        Object[][] kingvalues = new Object[10][2];
        while (timeOver == false) {
            depth++;
            if (depth==3)
            {
                timeOver=true;
                break;
                
            }
                value = negamax_optimized(myBoard, depth, true, -9000, 9000);

            kingvalues[depth][0] = value;
            kingvalues[depth][1] = m0temp;
            //System.out.println(m0temp.getMoveString() + ":"  + value);
//            if (timeOver == false) {
//                m0 = m0temp;
//            }
        }//endwhile

        int maxvalue = 0;
        ArrayList<Move> bestMoves = new ArrayList<Move>();

        for (int i = 1; i < (depth); i++) {
            value = (int) kingvalues[i][0];
            // System.out.println("Value: " +value + " Maxvalue: " +maxvalue);

            if (i == 1) {
                maxvalue = value;
                m0=(Move)kingvalues[i][1];
            }//endif
            
            if (value > maxvalue) {
                maxvalue = value;
                m0=(Move)kingvalues[i][1];
            }//endif

        }//endfor
        
         for (int i = 1; i < (depth); i++) {
            if(kingvalues[i][0]==maxvalue)
                bestMoves.add((Move)kingvalues[i][1]);
         }//endfor
        
         try
         {
         m0=bestMoves.get(myRandom(0, bestMoves.size()-1));
         }catch (Exception ex){}//endtry
                 
        System.out.println("Reached depth : " + depth);
        //  System.out.println("Move: " + m0.getMoveString());


        Move choosenMove = m0;
        System.out.println("Choosen Move: " + m0.getMoveString() + ": " + maxvalue);
        return choosenMove;
    }//end method

    public static Move chessBot_bestMove() {
        startTime = System.currentTimeMillis();
        loopCounter = 0;
        timeOver = false;

        bestMove(myBoard);

        Move choosenMove = m0;
        return choosenMove;
    }//end method

    public static Move bestMove(Board s1) {
        int d0 = 1;
        m0 = null;
        while (timeOver == false) {
            int v = -10000;
            int a0 = -10000;

            ArrayList<Move> moves = s1.getAllMoves();
            for (Move m : moves) {
                int v0 = -negamax(s1, d0, timeOver, -1, -a0);
                if (v > v0) {
                    v0 = v;
                }

                if (v0 > a0) {
                    a0 = v0;
                }

                if (v0 > v) {
                    m0 = m;
                }

                if (v0 > v) {
                    v = v0;
                }
            }//endfor
            d0++;
        }//endwhile
        return m0;
    }//endmethod

    public static int negamax(Board s, int depth, boolean top, int alpha, int beta) {
        int score = s.getScore();
        if ((score >= 9000) || (score <= -9000) || (depth <= 0) || (timeOver == true)) //is a terminal node or depth=0
        {
            return s.getScore();    /// * the heuristic value of node
        }

        long currentTime = System.currentTimeMillis();



        ArrayList<Move> moves = s.getAllMoves();

        Board s_ = new Board(s);
        Move m_ = moves.get(0);
        s_.move(m_);
        //   System.out.println(m_.getMoveString());
        //     System.out.println("Board Score of copy: " + s_.getScore());


        int v_ = -(negamax(s_, depth - 1, false, -beta, -alpha));

        if (top) {
            m0temp = m_;
        }

        int a0 = alpha;
        // System.out.println("********");
        for (Move m : moves) {// for each child of node
            loopCounter++;
            //System.out.println(loopCounter);
            if (loopCounter % 1000 == 0) {

                if ((currentTime - startTime) > 5000) {
                    timeOver = true;
                    System.out.println("used time: " + (currentTime - startTime));
                    break;

                }//endif
            }//endif



            s_ = new Board(s);
            s_.move(m);
            int v = -(negamax(s_, depth - 1, false, -beta, -a0));


            if (timeOver == true) {
                break;
            }

            // System.out.println(m.getMoveString() + ": " + v);
            if (v > v_) {
                v_ = v;

                if (top) {
                    m0temp = m;
                }


            }//endif   
            if (v_ > a0) {
                a0 = v;
            }



            if (v_ >= beta) {
                return v_;
            }


        }//endfor


        return v_;

    }//endmethod

    public static int negamax_optimized(Board s, int depth, boolean top, int alpha, int beta) {
        int score = s.getScore();
        if ((score >= 9000) || (score <= -9000) || (depth <= 0) || (timeOver == true)) //is a terminal node or depth=0
        {
            return s.getScore();    /// * the heuristic value of node
        }

        long currentTime = System.currentTimeMillis();



        ArrayList<Move> moves = s.getAllMoves();

        Board s_ = new Board(s);
        Move m_ = moves.get(0);
        s_.move(m_);
        //   System.out.println(m_.getMoveString());
        //     System.out.println("Board Score of copy: " + s_.getScore());


        int v_ = -(negamax_optimized(s_, depth - 1, false, -beta, -alpha));

        if (top) {
            m0temp = m_;
        }

        int a0 = alpha;
        // System.out.println("********");
        for (Move m : moves) {// for each child of node
            loopCounter++;
            //System.out.println(loopCounter);
            if (loopCounter % 1000 == 0) {

                if ((currentTime - startTime) > 5000) {
                    timeOver = true;
                    System.out.println("used time: " + (currentTime - startTime));
                    break;

                }//endif
            }//endif



            s_ = new Board(s);
            s_.move(m);
            int v = -(negamax_optimized(s_, depth - 1, false, -beta, -a0));


            if (timeOver == true) {
                break;
            }

            // System.out.println(m.getMoveString() + ": " + v);
            if (v > v_) {
                v_ = v;

                if (top) {
                    m0temp = m;
                }


            }//endif   
            if (v_ > a0) {
                a0 = v;
            }



            if (v_ >= beta) {
                return v_;
            }


        }//endfor


        return v_;

    }//endmethod

    public static int negamax_classic(Board s, int depth, boolean top) {
        int score = s.getScore();
        if ((score >= 9000) || (score <= -9000) || (depth <= 0) || (timeOver == true)) //is a terminal node or depth=0
        {
            return s.getScore();    /// * the heuristic value of node
        }
        long currentTime = System.currentTimeMillis();
        loopCounter++;
        //System.out.println(loopCounter);
        if (loopCounter % 1000 == 0) {

            if ((currentTime - startTime) > 4990) {
                timeOver = true;
                System.out.println("used time: " + (currentTime - startTime));
                return s.getScore();

            }//endif
        }//endif



        ArrayList<Move> moves = s.getAllMoves();

        Board s_ = new Board(s);
        Move m_ = moves.get(0);
        s_.move(m_);



        int v_ = -(negamax_classic(s_, depth - 1, false));

        if (top) {
            m0temp = m_;
        }
        // System.out.println("********");
        for (int i = 1; i < moves.size(); i++) {// for each child of node
            Move m = moves.get(i);
            s_ = new Board(s);
            s_.move(m);
            int v = -(negamax_classic(s_, depth - 1, false));

            if (timeOver == true) {
                break;
            }


            if (v > v_) {
                v_ = v;
                if (top) {
                    m0temp = m;
                }
            }//endif        
        }//endfor


        return v_;

    }//endmethod

    public static Move RandomChessBot() {
        Move choosenMove = null;
        ArrayList<Move> moves;
        moves = myBoard.getAllMoves();
        choosenMove = moves.get(myRandom(0, moves.size() - 1));

        return choosenMove;

    }//end method

    public static char sendServerMove(Client server, Move move) {
        char status = ' ';
        try {
            System.out.println("Movestring: " + move.getMoveString());
            server.sendMove(move.getMoveString());
        } catch (Exception ex) {
            System.out.println("!!!!!Exception sending Move!!!!!!");
            System.out.println(ex.toString());
        }//endtry

        status = myBoard.move(move);
        //System.out.println(status);
        return status;
    }//endmehtod

    public static char receiveServerMove(Client server) {
        String currentMoveString = null;
        char status = ' ';
        try {

            currentMoveString = server.getMove();
            //System.out.println("...getting move:" + currentMoveString);
            status = myBoard.move(currentMoveString);

        } catch (Exception ex) {
            System.out.println("!!!!!Exception receiving Move!!!!!!");
            //System.out.println(ex.toString());

        }//endtry
        System.out.println(currentMoveString);
        if (currentMoveString == null) {
            System.out.println("Hier");
            if (myBoard.getMoveNum() == 40) {
                status = '=';

            } else {
                if (myColor == 'W') {
                    status = 'B';
                } else {
                    status = 'W';
                }//endtry

            }//endif

        }//endif

        return status;
    }//endmehtod

    public static int myRandom(int low, int high) {
        return (int) (Math.random() * (high - low) + low);
    }//endmehthod

    public static String read(String text) {
        System.out.println(text);
        String input = "";
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            input = br.readLine();
        } catch (Exception e) {
            System.out.println(e);
        }
        return input;
    }//end read

    public static void initializeNetwork() {

        //######################################### Client Server   
        server = null;
        myColor = ' ';
        String tempColor;
        try {
            server = new Client("imcs.svcs.cs.pdx.edu", "3589", "megachess", "megachess");

            String whoisfirst = read("1 for offer \n2 for accept");


            while (myColor == ' ') {
                
                tempColor = read("Please choose your color:\n1 White\n2 Black ");
                if (tempColor.compareTo("1")==0) {
                    myColor = 'W';
                    System.out.println("You are White");
                } else if (tempColor.compareTo("2")==0) {
                    myColor = 'B';
                    System.out.println("You are Black");
                } else {
                    System.out.println("Falsche Auswahl!! Versuche es nochmal :)");
                }
            }//endwhile

            if (whoisfirst.compareTo("1") == 0) {
                // myColor = 'B';
                server.offer(myColor);
            } else if (whoisfirst.compareTo("2") == 0) {
                //myColor = 'W';
                String gameID = read("Please enter your game ID:");
                server.accept(gameID, myColor);
            }//endif


        } catch (Exception ex) {
            System.out.println(ex.toString());
            System.exit(1);
        }//endtry
        //###################### End Client Server

    }//endmehtod
}
